package lpca.utils.MazeGenerator 
{
	import adobe.utils.CustomActions;
	import lpca.utils.Point;
	import lpca.model.*;
	import lpca.utils.*;
	/**
	 * ...
	 * @author Figishe
	 */
	
	 
	 // FIXME: генератор не устраняет неиспользованные null-ячейки KMaze
	public class MazeGeneratorPattern implements IMazeGenerator // implements IMazeGenerator
	{
		private var patternMap: Vector.<Vector.<MazeGeneratorElement>>;
		
		private var elementsPerMazeX: int;
		private var elementsPerMazeY: int;
		
		private var vectorNull: Vector.<int>;
		private var vectorRandom: Vector.<int>;
		
		private var maze: IMaze;
		
		public function MazeGeneratorPattern() 
		{	
			vectorNull = new <int>[MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_NULL];
			vectorRandom = new <int>[MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM];
		}
		
		//var v:Vector.<int> = new <int>[0,1,2,];
		private function calculateSide(point: Point, direction: int): void
		// Расчет значения по заданной точке и стороне
		// Работает — не трогать!
		{
			if (point != null) 
			{ 
				/*
				if (patternMap[point.x][point.y] == null) // если в точке что-то есть
					trace('В переданной точке нет элемента.');
				*/
					
				if (patternMap[point.x][point.y].getSideValue(direction) == MazeGeneratorElement.SIDE_RANDOM)
				// если изначально значение установлено как случайное
				{
					var pointNext: Point = point.next(direction); // сдвигаем точку по направлению и сохраняем как pointNext
					if ((patternMap.length > pointNext.x) && (pointNext.x > 0) && (patternMap[pointNext.x].length > pointNext.y) && (pointNext.y > 0)) // если есть соседний элемент по направлению
					{
						var newValue: int = patternMap[pointNext.x][pointNext.y].getSideValue(Maze.mirroredDirection(direction)); // смотрим значение в прилегающей точке соседнего элемента по направлению
						if (newValue != MazeGeneratorElement.SIDE_RANDOM) // если прилегающая сторона соседнего элемента не случайная 
							{
								patternMap[point.x][point.y].setSideValue(direction, newValue); // копируем соседнее значение в наш элемент
							}
						else   
							patternMap[point.x][point.y].setRandomSideValue(direction);	// иначе вычисляем случайное для стороны
					}
					else
						patternMap[point.x][point.y].setRandomSideValue(direction); // если сбоку ничего нет, то ставим что угодно
				}
			}
		}
		
		private function addBounds(): void
		// установка нулевых элементов по краям
		{
			for (var x: int = 2; x <= elementsPerMazeX - 1; x++)
			{
				var vectorUp: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM];
				var vectorDown: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_RANDOM];
				
				//var elementUp: MazeGeneratorElement = new MazeGeneratorElement(vectorUp); 
				//var elementDown: MazeGeneratorElement = new MazeGeneratorElement(vectorDown);
				
				patternMap[x][1] =  new MazeGeneratorElement(vectorUp);
				patternMap[x][elementsPerMazeY] =  new MazeGeneratorElement(vectorDown);
			}
			
			for (var y: int = 2; y <= elementsPerMazeY - 1; y++)
			{
				var vectorLeft: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_NULL];
				var vectorRight: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM];
				
				//var elementLeft: MazeGeneratorElement = new MazeGeneratorElement(vectorLeft); 
				//var elementRight: MazeGeneratorElement = new MazeGeneratorElement(vectorRight);
				
				patternMap[1][y] =  new MazeGeneratorElement(vectorLeft); 
				patternMap[elementsPerMazeX][y] =  new MazeGeneratorElement(vectorRight);
			}
			
			// Угловые элементы
			var vectorCorner1: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_RANDOM];
			var vectorCorner2: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_NULL];
			var vectorCorner3: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM];
			var vectorCorner4: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_NULL, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_NULL];
			
			patternMap[1][1]                               = new MazeGeneratorElement(vectorCorner4);
			patternMap[elementsPerMazeX][1]                = new MazeGeneratorElement(vectorCorner3);
			patternMap[1][elementsPerMazeY]                = new MazeGeneratorElement(vectorCorner2);
			patternMap[elementsPerMazeX][elementsPerMazeY] = new MazeGeneratorElement(vectorCorner1); 
			
		}
		
		private function fillCenter(): void
		// заполнение области внутри границ пустыми "случайными" элементами
		{
			var newElement: MazeGeneratorElement = new MazeGeneratorElement();
			for (var x: int = 2; x <= elementsPerMazeX - 1; x++)
			{
				for (var y: int = 2; y <= elementsPerMazeY - 1; y++)
				{
					
					patternMap[x][y] =  new MazeGeneratorElement(vectorRandom);
				}
			}
			//patternMap[3][2].setSideValue(0, 7);
		}
		
		private function addStartElement(): void
		{
			//var vector1234: Vector.<int> = new <int>[MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM, MazeGeneratorElement.SIDE_RANDOM];
			//var elementStart: MazeGeneratorElement = new MazeGeneratorElement(vector1234);//= elementRandom;
			//elementStart.setSideValue(KMaze.DIR_LEFT, 2); // 2 - второй с левой стороны, т.е не первый угловой, а ниже
			patternMap[1][elementsPerMazeY - 1] = new MazeGeneratorElement(vectorRandom); // ставим слева снизу
		}
		
		private function addFinishElement(): void
		{
			//var elementFinish: MazeGeneratorElement = elementRandom;
			//elementFinish.setSideValue(KMaze.DIR_RIGHT, 2);
			patternMap[elementsPerMazeX][2] = new MazeGeneratorElement(vectorRandom); // ставим справа сверху
		}
		
		public function generateMaze(maze: IMaze, mazeGenSet: MazeGeneratorSet): void
		{
			this.maze = maze;
			maze.fillWith(new Cell(Cell.CELL_WALL));
			elementsPerMazeX = Math.floor(maze.getSizeX() / MazeGeneratorSet.ELEMENT_SIZE);
			elementsPerMazeY = Math.floor(maze.getSizeY() / MazeGeneratorSet.ELEMENT_SIZE);
					
			this.patternMap = new Vector.<Vector.<MazeGeneratorElement>>(elementsPerMazeX); // создаем новый вектор для элементов-шаблонов
			
			for (var x: int = 1; x <= elementsPerMazeX; x++)
				patternMap[x] = new Vector.<MazeGeneratorElement>(elementsPerMazeY);
			
			fillCenter();
			addBounds();
			//addStartElement();
			//addFinishElement();
			
			var point: Point;
			
			// генерируем patternMap
			for (x = 1; x <= elementsPerMazeX; x++) // цикл по столбцам
				for (var y: int = 1; y <= elementsPerMazeY; y++) // цикл по строкам
				{
					point = new Point(x, y); 
					for (var direction: int = maze.getMinDirection(); direction <= maze.getMaxDirection(); direction++)
						calculateSide(point, direction); // считаем значения всех точек во всех направлениях
					//trace('Вставка матрицы в позицию', x, ',', y);
					maze.insertMatrix((x - 1) * MazeGeneratorSet.ELEMENT_SIZE, (y - 1) * MazeGeneratorSet.ELEMENT_SIZE, mazeGenSet.getClassRndPuzzle(patternMap[x][y].getSideValue(0), patternMap[x][y].getSideValue(1), patternMap[x][y].getSideValue(2), patternMap[x][y].getSideValue(3)))
				}
				
			x = elementsPerMazeX / 2 - 1;
			y = elementsPerMazeY / 2 - 1;
			
			for (var i: int = 0; i < MazeGeneratorSet.ELEMENT_SIZE; i++) 
				for (var j: int = 0; j <= MazeGeneratorSet.ELEMENT_SIZE; j++) 
				{
					point = new Point(MazeGeneratorSet.ELEMENT_SIZE * x + i, MazeGeneratorSet.ELEMENT_SIZE * y + j);
					if (maze.getCell(point).value == Cell.CELL_EMPTY)
					{
						maze.setStartPoint(point);
						break;
					}
				}
			
			// устранение пересечений стен по диагонали
			//FIXME: а оно вообще работает?
			for (i = 2; i < maze.getSizeX() - 1 ; i++)	
				for (j = 2; j < maze.getSizeY() - 1; j++)
				{
					point = new Point(i, j); 
					if (( (maze.getCell(point).value == Cell.CELL_WALL) && (maze.getNearestCell(point, Maze.DIR_LEFT).value == Cell.CELL_EMPTY) && (maze.getNearestCell(point, Maze.DIR_UP).value == Cell.CELL_EMPTY) && (maze.getCell(new Point(point.x - 1, point.y - 1)).value == Cell.CELL_WALL) ) || 
					   ((maze.getCell(point).value == Cell.CELL_WALL) && (maze.getNearestCell(point, Maze.DIR_LEFT).value == Cell.CELL_EMPTY) && (maze.getNearestCell(point, Maze.DIR_DOWN).value == Cell.CELL_EMPTY) && (maze.getCell(new Point(point.x - 1, point.y + 1)).value == Cell.CELL_WALL)))
					{
						maze.setCell(point, new Cell(Cell.CELL_EMPTY));
					}
				}
			//maze.setStartPoint(new Point(x, y))
			//TODO: из patternMap и паззлов в готовый KMaze
		}
		
		/*
		public function show(): void // вывод шаблонов
		{
			var str: String;
			var val: int;
			var val2: int;
			
			for (var y: int = 1; y <= elementsPerMazeY; y++)
			{
				str = '';
				for (var x: int = 1; x <= elementsPerMazeX; x++) 
					{
						val = patternMap[x][y].getSideValue(KMaze.DIR_UP);
						str += '┌' + val.toString() + '┐ ';
					}
				trace(str);
				str = '';
				for (x = 1; x <= elementsPerMazeX; x++) 
					{
						val = patternMap[x][y].getSideValue(KMaze.DIR_LEFT);
						val2 = patternMap[x][y].getSideValue(KMaze.DIR_RIGHT);
						str += val.toString() + ' ' + val2.toString() + ' ';
					}
				trace(str);
				str = '';
				for (x = 1; x <= elementsPerMazeX; x++) 
					{
						val = patternMap[x][y].getSideValue(KMaze.DIR_DOWN);
						str += '└' + val.toString() + '┘ ';
					}
				trace(str);
			}
		}
		*/
		
	}

}